package edu.uci.ics.ai.maze.views;

import edu.uci.ics.ai.maze.controllers.SearchContext;
import edu.uci.ics.ai.maze.models.GameModel;
import edu.uci.ics.ai.maze.models.Vertex;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;

public class VisibleVertexDialogModel extends Observable {

  private final SearchContext context;
  private final List<String> visibleInfo;

  //Use these to keep track of the different button states in the dialog
  private final boolean[] startNavCtrlState;
  private final boolean[] prevNavCtrlState;
  private final boolean[] nextNavCtrlState;
  private final boolean[] endNavCtrlState;

  private Vertex[] visArray;
  private Vertex curVertex;
  private int selIndex;
  private int numVisible;
  private int curVIndex;
  private boolean[] curNavCtrlState;
  
  public VisibleVertexDialogModel(GameModel model) {
    this.context = model.getContext();
    this.visibleInfo = new ArrayList<String>();

    startNavCtrlState = new boolean[4];
    startNavCtrlState[0] = false;
    startNavCtrlState[1] = false;
    startNavCtrlState[2] = true;
    startNavCtrlState[3] = true;

    prevNavCtrlState = new boolean[4];
    prevNavCtrlState[0] = true;
    prevNavCtrlState[1] = true;
    prevNavCtrlState[2] = true;
    prevNavCtrlState[3] = true;

    nextNavCtrlState = new boolean[4];
    nextNavCtrlState[0] = true;
    nextNavCtrlState[1] = true;
    nextNavCtrlState[2] = true;
    nextNavCtrlState[3] = true;

    endNavCtrlState = new boolean[4];
    endNavCtrlState[0] = true;
    endNavCtrlState[1] = true;
    endNavCtrlState[2] = false;
    endNavCtrlState[3] = false;
  }

  public void calcVisibleInfo(Vertex curVertex) {
    int numberOfVertices = context.getVertexCount();
    this.curVertex = curVertex;

    Vertex[] tempArray = new Vertex[numberOfVertices + 2];
    numVisible = 0;

    if (context.isVisible(curVertex, context.getStart())) {
      tempArray[0] = context.getStart();
      numVisible = 1;
    }

    for (Vertex v : context.getVertices()) {
      if (context.isVisible(curVertex, v)) {
        tempArray[numVisible++] = v;
      }
    }

    if (context.isVisible(curVertex, context.getGoal())) {
      tempArray[numVisible++] = context.getGoal();

    }

    visArray = new Vertex[numVisible];
    System.arraycopy(tempArray, 0, visArray, 0, numVisible);

    visibleInfo.clear();
    for (Vertex v : visArray) {
      visibleInfo.add(v.toString());
    }
    setChanged();
    notifyObservers(GameModel.Observations.UPDATE_VIS_VERTEX_DIALOG);
  }

  public List<String> getVisibleInfo() {
    return visibleInfo;
  }

  public Vertex[] getVisibleVertices() {
    return visArray;
  }

  public int getNumVisibleVertices() {
    return numVisible;
  }

  public Vertex getStart() {
    curVIndex = -1;
    curNavCtrlState = startNavCtrlState;
    return context.getStart();
  }

  public Vertex getEnd() {
    curVIndex = context.getVertexCount();
    curNavCtrlState = endNavCtrlState;
    return context.getGoal();
  }

  public Vertex getPrev() {
    curVIndex--;
    if (curVIndex < 0) {
      return getStart();
    } else if (curVIndex >= 0 && curVIndex < context.getVertexCount()) {
      curNavCtrlState = prevNavCtrlState;
      return context.getVertices().get(curVIndex);
    } else if (curVIndex >= context.getVertexCount()) {
      return getEnd();
    }
    return null;
  }

  public Vertex getNext() {
    curVIndex++;
    if (curVIndex < 0) {
      return getStart();
    } else if (curVIndex >= 0 && curVIndex < context.getVertexCount()) {
      curNavCtrlState = nextNavCtrlState;
      return context.getVertices().get(curVIndex);
    } else if (curVIndex >= context.getVertexCount()) {
      return getEnd();
    }
    return null;
  }

  public void resetState() {
    visArray = null;
    visibleInfo.clear();
    curVertex = null;
    numVisible = 0;
    curVIndex = -1;//start state
    selIndex = -1;
    curNavCtrlState = startNavCtrlState;
    setChanged();
    notifyObservers(GameModel.Observations.UPDATE_VISIBLE_VERTICES);
  }

  public void setSelIndex(int index) {
    selIndex = index;
    setChanged();
    notifyObservers(GameModel.Observations.UPDATE_VISIBLE_VERTICES);
  }

  public int getSelVisVert() {
    return selIndex;
  }

  public int getNumVisVert() {
    return numVisible;
  }

  public boolean[] getNavCtrlState() {
    return curNavCtrlState;
  }

  public Vertex getCurVertex() {
    return curVertex;
  }
}
